home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / internet / other / ka9q / nhclb120.zoo / telnet.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-19  |  17.1 KB  |  834 lines

  1. #include <stdio.h>
  2. #include <ctype.h>
  3. #include "config.h"
  4. #include "global.h"
  5. #include "mbuf.h"
  6. #include "timer.h"
  7. #include "icmp.h"
  8. #include "netuser.h"
  9. #include "tcp.h"
  10. #include "telnet.h"
  11. #include "session.h"
  12. #include "ftp.h"
  13. #include "iface.h"
  14. #include "ax25.h"
  15. #include "lapb.h"
  16. #include "finger.h"
  17. #include "nr4.h"
  18. #ifdef    UNIX
  19. #include <string.h>
  20. #endif
  21.  
  22. #define    CTLZ    26
  23.  
  24. #if !defined( _MEMORY_H) && !defined(_STRING_H)
  25. char *memchr();
  26. #endif
  27.  
  28.  
  29. static free_telnet();
  30. static void answer();
  31. extern char nospace[];
  32. extern char badhost[];
  33. int refuse_echo = 0;
  34. int unix_line_mode = 0;    /* if true turn <cr> to <nl> when in line mode */
  35. int debug_options = 0;
  36. extern FILE *trfp;            /* file pointer used for tracing */
  37. void suboption();
  38.  
  39. char *t_options[] = {
  40.     "BINARY", "ECHO", "RCP", "SGA",    "NAMS",    "STATUS", "TM",
  41.     "RCTE", "NAOL", "NAOP", "NAOCRD", "NAOHTS", "NAOHTD", "NAOFFD", 
  42.     "NAOVTS", "NAOVTD", "NAOLFD", "XASCII", "LOGOUT", "BM", "DET", 
  43.     "SUPDUP", "SUPDUPOUOT", "SNDLOC", "TTYPE", "EOR", "TACACS", 
  44.     "OUTMARK", "LOCNUM", "TN3270", "X3PAD", "NAWS", "TSPEED",
  45.     "LFLOW", "LINEMODE", "XDISPLOC"
  46. };
  47.  
  48. /* Execute user telnet command */
  49. int
  50. dotelnet(argc,argv)
  51. int argc;
  52. char *argv[];   /* argv[1] = host,  argv[2] = service */
  53. {
  54.     void t_state(),rcv_char(),tn_tx();
  55.     char *inet_ntoa();
  56.     int32 resolve();
  57.     int send_tel();
  58.         int unix_send_tel();
  59.     struct session *s;
  60.     struct telnet *tn;
  61.     struct tcb *tcb;
  62.     struct socket lsocket,fsocket;
  63.  
  64.     lsocket.address = ip_addr;
  65.     lsocket.port = lport++;
  66.     printf("Lookup ...");
  67.     if((fsocket.address = resolve(argv[1])) == 0){
  68.         printf(badhost,argv[1]);
  69.         return 1;
  70.     }
  71.     
  72.     if(argc < 3)
  73.         fsocket.port = TELNET_PORT;
  74.     else
  75.         fsocket.port = service_code(argv[2]);
  76.     if(fsocket.port<0){
  77.             printf("Unknown service  %s\n", argv[2]);
  78.         return(1);
  79.           }
  80.     printf(" done. Trying to connect to %s ...\n",
  81.            inet_ntoa( fsocket.address));
  82.     /* Allocate a session descriptor */
  83.     if((s = newsession()) == NULLSESSION){
  84.         printf("Too many sessions\n");
  85.         return 1;
  86.     }
  87.     if((s->name = malloc((unsigned)strlen(argv[1])+1)) != NULLCHAR)
  88.         strcpy(s->name,argv[1]);
  89.     s->type = TELNET;
  90.     if ((refuse_echo == 0) && (unix_line_mode != 0)) {
  91.         s->parse = unix_send_tel;
  92.     } else {
  93.         s->parse = send_tel;
  94.     }
  95.     current = s;
  96.  
  97.     /* Create and initialize a Telnet protocol descriptor */
  98.     if((tn = (struct telnet *)calloc(1,sizeof(struct telnet))) == NULLTN){
  99.         printf(nospace);
  100.         s->type = FREE;
  101.         return 1;
  102.     }
  103.     tn->session = s;    /* Upward pointer */
  104.     tn->state = TS_DATA;
  105.     s->cb.telnet = tn;    /* Downward pointer */
  106.  
  107.     tcb = open_tcp(&lsocket,&fsocket,TCP_ACTIVE,0,
  108.      rcv_char,tn_tx,t_state,0,(char *)tn);
  109.  
  110.     tn->tcb = tcb;    /* Downward pointer */
  111.     go_mode();
  112.     return 0;
  113. }
  114.  
  115. /* Process typed characters */
  116. int
  117. unix_send_tel(buf,n)
  118. char *buf;
  119. int16 n;
  120. {
  121.     int i;
  122.  
  123.     for (i=0; (i<n) && (buf[i] != '\r'); i++)
  124.         ;
  125.     if (buf[i] == '\r') {
  126.         buf[i] = '\n';
  127.         n = i+1;
  128.     }
  129.     send_tel(buf,n);
  130. }
  131. int
  132. send_tel(buf,n)
  133. char *buf;
  134. int16 n;
  135. {
  136.     struct mbuf *bp;
  137.     if(current == NULLSESSION || current->cb.telnet == NULLTN
  138.      || current->cb.telnet->tcb == NULLTCB)
  139.         return;
  140.     /* If we're doing our own echoing and recording is enabled, record it */
  141.     if(!current->cb.telnet->remote[TN_ECHO] && current->record != NULLFILE)
  142.         fwrite(buf,1,(int)n,current->record);
  143.     bp = qdata(buf,n);
  144.     send_tcp(current->cb.telnet->tcb,bp);
  145. }
  146.  
  147. /* set up correct tty modes */
  148. int
  149. tel_setterm(tn)
  150. register struct telnet *tn;
  151. {
  152.     if(current->cb.telnet->remote[TN_ECHO]) {
  153.         raw();    /* other end is echoing, we're raw */
  154.         if (tn->lflow)
  155.             flowon();
  156.         else
  157.             flowoff();
  158.     } else {
  159.         cooked();
  160.         flowdefault();
  161.     }
  162. }
  163.  
  164. /* 
  165.  * stdio has no way to flush.  So do our own.
  166.  */
  167.  
  168. /* might as well make the buffer big enough for an Ethernet packet */
  169. #define TBSIZE 2048
  170. char termbuf[TBSIZE];
  171. char *termbufp = termbuf;
  172. char *termbufe = termbuf + TBSIZE;
  173.  
  174. int
  175. tnputchar(c)
  176. int c;
  177. {
  178.   if (termbufp >= termbufe) {
  179.     write(1, termbuf, TBSIZE);
  180.     termbufp = termbuf;
  181.   }
  182.   *termbufp++ = c;
  183. }
  184.  
  185. /* send out buffered data */
  186. int
  187. tnflush()
  188. {
  189.   if (termbufp > termbuf)
  190.     write(1, termbuf, termbufp - termbuf);
  191.   termbufp = termbuf;
  192. }
  193.  
  194. /* clear output -- should also do clearout to do Unix clear */
  195. int
  196. tnclear()
  197. {
  198.   termbufp = termbuf;
  199. }
  200.  
  201. /* Process incoming TELNET characters */
  202. int
  203. tel_input(tn,bp)
  204. register struct telnet *tn;
  205. struct mbuf *bp;
  206. {
  207.     char c;
  208.     void doopt(),dontopt(),willopt(),wontopt(),answer();
  209.     FILE *record;
  210.  
  211.  
  212.     /* Optimization for very common special case -- no special chars */
  213.     if(tn->state == TS_DATA){
  214.         while(bp != NULLBUF && memchr(bp->data,IAC,(int)bp->cnt) == NULLCHAR){
  215.             if (! tn->outsup) {
  216.                 if((record = tn->session->record) != NULLFILE)
  217.                     fwrite(bp->data,1,(int)bp->cnt,record);
  218.                 while(bp->cnt-- != 0)
  219.                     tnputchar(*bp->data++);
  220.             }
  221.             bp = free_mbuf(bp);
  222.         }
  223.     }
  224.     while(pullup(&bp,&c,1) == 1){
  225.         switch(tn->state){
  226.         case TS_DATA:
  227.             if(uchar(c) == IAC){
  228.                 tn->state = TS_IAC;
  229.             } else {
  230. #ifdef undef
  231.                 if(!tn->remote[TN_TRANSMIT_BINARY])
  232.                     c &= 0x7f;
  233. #endif
  234.                 if (! tn->outsup) {
  235.                     tnputchar(c);
  236.                     if((record = tn->session->record) 
  237.                        != NULLFILE)
  238.                         putc(c,record);
  239.                 }
  240.             }
  241.             break;
  242.         case TS_IAC:
  243. process_iac:
  244.             switch(uchar(c)){
  245.             case WILL:
  246.                 tn->state = TS_WILL;
  247.                 break;
  248.             case WONT:
  249.                 tn->state = TS_WONT;
  250.                 break;
  251.             case DO:
  252.                 tn->state = TS_DO;
  253.                 break;
  254.             case DONT:
  255.                 tn->state = TS_DONT;
  256.                 break;
  257.             case TN_DM:
  258.                 /*
  259.                  * if outsup > 1, we are still in urgent
  260.                  * data, so DM is ignored
  261.                  */
  262.                 if (tn->outsup == 1) {
  263.                     tn->outsup = 0;
  264.                     if (debug_options)
  265.                         fprintf(trfp, "[End of urgent data]\n");
  266.                 }
  267.                 tn->state = TS_DATA;
  268.                 break;
  269.             case SB:
  270.                 SB_CLEAR();
  271.                 tn->state = TS_SB;
  272.                 break;
  273.             case IAC:
  274.                 tnputchar(c);
  275.                 tn->state = TS_DATA;
  276.                 break;
  277.             default:
  278.                 tn->state = TS_DATA;
  279.                 break;
  280.             }
  281.             break;
  282.         case TS_WILL:
  283.             willopt(tn,c);
  284.             tn->state = TS_DATA;
  285.             break;
  286.         case TS_WONT:
  287.             wontopt(tn,c);
  288.             tn->state = TS_DATA;
  289.             break;
  290.         case TS_DO:
  291.             doopt(tn,c);
  292.             tn->state = TS_DATA;
  293.             break;
  294.         case TS_DONT:
  295.             dontopt(tn,c);
  296.             tn->state = TS_DATA;
  297.             break;
  298.             case TS_SB:
  299.             if (uchar(c) == IAC) {
  300.                 tn->state = TS_SE;
  301.                 break;
  302.             } else {
  303.                 SB_ACCUM(c);
  304.             }
  305.             break;
  306.         case TS_SE:
  307.             if (uchar(c) != SE) {
  308.               if (uchar(c) != IAC) {
  309.                 /*
  310.                  * This is an error.  We only expect to get
  311.                  * "IAC IAC" or "IAC SE".  Several things may
  312.                  * have happend.  An IAC was not doubled, the
  313.                  * IAC SE was left off, or another option got
  314.                  * inserted into the suboption are all possibilities.
  315.                  * If we assume that the IAC was not doubled,
  316.                  * and really the IAC SE was left off, we could
  317.                  * get into an infinate loop here.  So, instead,
  318.                  * we terminate the suboption, and process the
  319.                  * partial suboption if we can.
  320.                  */
  321.                 SB_ACCUM(IAC);
  322.                 SB_ACCUM(c);
  323.                 tn->subpointer -= 2;
  324.                 SB_TERM();
  325.                 suboption(tn);    /* handle sub-option */
  326.                 tn->state = TS_IAC;
  327.                 goto process_iac;
  328.               }
  329.               SB_ACCUM(c);
  330.               tn->state = TS_SB;
  331.             } else {
  332.               SB_ACCUM(IAC);
  333.               SB_ACCUM(SE);
  334.               tn->subpointer -= 2;
  335.               SB_TERM();
  336.               suboption(tn);    /* handle sub-option */
  337.               tn->state = TS_DATA;
  338.             }
  339.             break;
  340.         }
  341.     }
  342. }
  343.  
  344. /* Telnet receiver upcall routine */
  345. void
  346. rcv_char(tcb,cnt)
  347. register struct tcb *tcb;
  348. int16 cnt;
  349. {
  350.     struct mbuf *bp;
  351.     struct telnet *tn;
  352.     FILE *record;
  353. #ifdef    FLOW
  354.     extern int ttyflow;
  355. #endif
  356.     if((tn = (struct telnet *)tcb->user) == NULLTN){
  357.         /* Unknown connection; ignore it */
  358.         return;
  359.     }
  360.     /* Hold output if we're not the current session */
  361.     if(mode != CONV_MODE || current == NULLSESSION
  362. #ifdef    FLOW
  363.      || !ttyflow    /* Or if blocked by keyboard input -- hyc */
  364. #endif
  365.      || current->type != TELNET || current->cb.telnet != tn)
  366.         return;
  367.  
  368. /*
  369.  * Urgent data is done by combination of the TCP level and this code.
  370.  * The TCP level sets URGCUR and tcb->up (urgent pointer), but we
  371.  * clear it at this level.  We want to clear it when we've taken
  372.  * data beyond the urgent pointer, and only here are we in a position
  373.  * to control that.  The code is better here anyway, because other
  374.  * applications may treat the urgent pointer differently.  Rlogin
  375.  * for example, would have rather different code.  This implementation
  376.  * is a layering violation, but lets us get very good results.
  377.  */
  378.     if (tcb->flags & URGCUR) {
  379.         /* we are in urgent data */
  380.         int32 start = tcb->rcv.nxt - tcb->rcvcnt;
  381.         int32 count;
  382.  
  383. /*
  384.  * we use rcv.up - 2  as the end of urgent data so that the DM (which
  385.  * is 2 characters isn't included.  Actually one could argue that it should
  386.  * be - 1 because of the modification to the definition of urgent 
  387.  * introduced in the host requirements RFC and other official modifications,
  388.  * but - 2 is safe.  Note that outsup == 2 indicates that we're still in
  389.  * urgent data, so we should ignore any DM.
  390.  */
  391.         if (seq_gt (tcb->rcv.up - 2, start)) {
  392.             /* 
  393.              * at least some data in this segment is urgent.
  394.              * clear output and set outsup to suppress output.
  395.              */
  396.             tnclear();
  397.             clearout();
  398.             tn->outsup = 2;
  399.             /* see how much data is urgent */
  400.             count = (tcb->rcv.up - 2) - start;
  401.             if (count > cnt)
  402.                 count = cnt;
  403.             if(recv_tcp(tcb,&bp,count) > 0) { /* get from TCP */
  404.                 tel_input(tn,bp);  /* process through telnet */
  405.                 /* any data beyond urgent? */
  406.                 cnt -= count;
  407.                 if (cnt > 0) {
  408.                     /*
  409.                      * say we're no longer in urgent
  410.                      * data.  outsup 1 means to suppress
  411.                      * output until next DM.
  412.                      */
  413.                     tcb->flags &= ~URGCUR;
  414.                     tn->outsup = 1;
  415.                     if(recv_tcp(tcb,&bp,cnt) > 0)
  416.                         tel_input(tn,bp);
  417.                 }
  418.             }
  419.         } else {
  420.             /* 
  421.              * no more urgent data.  Clear urgent flag and
  422.              * set so suppress output stops at next DM
  423.              */
  424.             tcb->flags &= ~URGCUR;
  425.             tn->outsup = 1;
  426.             if(recv_tcp(tcb,&bp,cnt) > 0)
  427.                 tel_input(tn,bp);
  428.             }
  429.     } else {
  430.     /* normal (no urgent data) case */
  431.     if(recv_tcp(tcb,&bp,cnt) > 0)
  432.         tel_input(tn,bp);
  433.         }
  434.  
  435.     tnflush();  /* flush tty output buffer */
  436.     if((record = tn->session->record) != NULLFILE)
  437.         fflush(record);
  438. }
  439. /* Handle transmit upcalls. Used only for file uploading */
  440. void
  441. tn_tx(tcb,cnt)
  442. struct tcb *tcb;
  443. int16 cnt;
  444. {
  445.     struct telnet *tn;
  446.     struct session *s;
  447.     struct mbuf *bp;
  448.     int size;
  449.  
  450.     if((tn = (struct telnet *)tcb->user) == NULLTN
  451.      || (s = tn->session) == NULLSESSION
  452.      || s->upload == NULLFILE)
  453.         return;
  454.     if((bp = alloc_mbuf(cnt)) == NULLBUF)
  455.         return;
  456.     if((size = fread(bp->data,1,(int)cnt,s->upload)) > 0){
  457.         bp->cnt = (int16)size;
  458.         send_tcp(tcb,bp);
  459.     } else {
  460.         free_p(bp);
  461.     }
  462.     if(size != cnt){
  463.         /* Error or end-of-file */
  464.         fclose(s->upload);
  465.         s->upload = NULLFILE;
  466.         free(s->ufile);
  467.         s->ufile = NULLCHAR;
  468.     }
  469. }
  470.  
  471. /* State change upcall routine */
  472. /*ARGSUSED*/
  473. void
  474. t_state(tcb,old,new)
  475. register struct tcb *tcb;
  476. char old,new;
  477. {
  478.     struct telnet *tn;
  479.     char notify = 0;
  480.     extern char *tcpstates[];
  481.     extern char *reasons[];
  482.     extern char *unreach[];
  483.     extern char *exceed[];
  484.  
  485.     /* Can't add a check for unknown connection here, it would loop
  486.      * on a close upcall! We're just careful later on.
  487.      */
  488.     tn = (struct telnet *)tcb->user;
  489.  
  490.     if(current != NULLSESSION && current->type == TELNET && current->cb.telnet == tn)
  491.     {
  492.         notify = 1;
  493.         cooked();    /* prettify things... -- hyc */
  494.     }
  495.  
  496.     switch(new){
  497.     case CLOSE_WAIT:
  498.         if(notify)
  499.             printf("%s\n",tcpstates[new]);
  500.         close_tcp(tcb);
  501.         break;
  502.     case CLOSED:    /* court adjourned */
  503.         if(notify){
  504.             printf("%s (%s",tcpstates[new],reasons[tcb->reason]);
  505.             if(tcb->reason == NETWORK){
  506.                 switch(tcb->type){
  507.                 case DEST_UNREACH:
  508.                     printf(": %s unreachable",unreach[tcb->code]);
  509.                     break;
  510.                 case TIME_EXCEED:
  511.                     printf(": %s time exceeded",exceed[tcb->code]);
  512.                     break;
  513.                 }
  514.             }
  515.             printf(")\n");
  516.             cmdmode();
  517.         }
  518.         del_tcp(tcb);
  519.         if(tn != NULLTN)
  520.             free_telnet(tn);
  521.         break;
  522.     default:
  523.         if(notify)
  524.             printf("%s\n",tcpstates[new]);
  525.         break;
  526.     }
  527.     /* not sure which of these is needed */
  528.     tnflush();  
  529.     fflush(stdout);
  530. }
  531. /* Delete telnet structure */
  532. static
  533. free_telnet(tn)
  534. struct telnet *tn;
  535. {
  536.     if(tn->session != NULLSESSION)
  537.         freesession(tn->session);
  538.  
  539.     if(tn != NULLTN)
  540.         free((char *)tn);
  541. }
  542.  
  543. /* The guts of the actual Telnet protocol: negotiating options */
  544. void
  545. willopt(tn,opt)
  546. struct telnet *tn;
  547. char opt;
  548. {
  549.     int ack;
  550.     void answer();
  551.  
  552.     if (debug_options) {
  553.         fprintf(trfp, "[Recv: will ");
  554.         if(uchar(opt) <= NOPTIONS)
  555.             fprintf(trfp, "%s]\n",t_options[opt]);
  556.         else
  557.             fprintf(trfp, "%u]\n",opt);
  558.     }
  559.     
  560.     switch(uchar(opt)){
  561.     case TN_TRANSMIT_BINARY:
  562.     case TN_ECHO:
  563.     case TN_SUPPRESS_GA:
  564.         if(tn->remote[uchar(opt)] == 1)
  565.             return;        /* Already set, ignore to prevent loop */
  566.         if(uchar(opt) == TN_ECHO){
  567.             if(refuse_echo){
  568.                 /* User doesn't want to accept */
  569.                 ack = DONT;
  570.                 break;
  571.             } else {
  572.                 /* must set before calling tel_setterm */
  573.                 tn->remote[uchar(opt)] = 1;
  574.                 tel_setterm(tn); /* raw mode etc. */
  575.             }
  576.         } else
  577.             tn->remote[uchar(opt)] = 1;
  578.         ack = DO;            
  579.         break;
  580.     default:
  581.         ack = DONT;    /* We don't know what he's offering; refuse */
  582.     }
  583.     answer(tn,ack,opt);
  584. }
  585. void
  586. wontopt(tn,opt)
  587. struct telnet *tn;
  588. char opt;
  589. {
  590.     void answer();
  591.  
  592.     if (debug_options) {
  593.         fprintf(trfp, "[Recv: wont ");
  594.         if(uchar(opt) <= NOPTIONS)
  595.             fprintf(trfp, "%s]\n",t_options[opt]);
  596.         else
  597.             fprintf(trfp, "%u]\n",opt);
  598.     }
  599.  
  600.     if(uchar(opt) <= NOPTIONS){
  601.         if(tn->remote[uchar(opt)] == 0)
  602.             return;        /* Already clear, ignore to prevent loop */
  603.         tn->remote[uchar(opt)] = 0;
  604.         if(uchar(opt) == TN_ECHO)
  605.             tel_setterm(tn);  /* cooked mode, etc. */
  606.     }
  607.     answer(tn,DONT,opt);    /* Must always accept */
  608. }
  609. void
  610. doopt(tn,opt)
  611. struct telnet *tn;
  612. char opt;
  613. {
  614.     void answer();
  615.     int ack;
  616.  
  617.     if (debug_options) {
  618.         fprintf(trfp, "[Recv: do ");
  619.         if(uchar(opt) <= NOPTIONS)
  620.             fprintf(trfp, "%s]\n",t_options[opt]);
  621.         else
  622.             fprintf(trfp, "%u]\n",opt);
  623.     }
  624.  
  625.     switch(uchar(opt)){
  626.     case TN_TTYPE:
  627.         if(tn->local[uchar(opt)] == 1)
  628.             return;        /* Already set, ignore to prevent loop */
  629.         tn->local[uchar(opt)] = 1;
  630. #if 0
  631.         ack = WILL;
  632. #else /* dje hack */
  633.         ack = WONT;
  634. #endif
  635.         break;
  636.  
  637.     case TN_LFLOW:
  638.         if(tn->local[uchar(opt)] == 1)
  639.             return;        /* Already set, ignore to prevent loop */
  640.         tn->local[uchar(opt)] = 1;
  641.         tn->lflow = 1;  /* protocol says initialize to known state */
  642.         tel_setterm(tn);  /* enable flow */
  643.         ack = WILL;
  644.         break;
  645.     default:
  646.         ack = WONT;    /* Don't know what it is */
  647.     }
  648.     answer(tn,ack,opt);
  649. }
  650. void
  651. dontopt(tn,opt)
  652. struct telnet *tn;
  653. char opt;
  654. {
  655.     void answer();
  656.  
  657.     if (debug_options) {
  658.         fprintf(trfp, "[Recv: dont ");
  659.         if(uchar(opt) <= NOPTIONS)
  660.             fprintf(trfp, "%s]\n",t_options[opt]);
  661.         else
  662.             fprintf(trfp, "%u]\n",opt);
  663.     }
  664.  
  665.     if(uchar(opt) <= NOPTIONS){
  666.         if(tn->local[uchar(opt)] == 0){
  667.             /* Already clear, ignore to prevent loop */
  668.             return;
  669.         }
  670.         tn->local[uchar(opt)] = 0;
  671.     }
  672.     answer(tn,WONT,opt);
  673. }
  674.  
  675. void
  676. suboption(tn)
  677. register struct telnet *tn;
  678. {
  679.    if (debug_options) {
  680.         int opt = SB_PEEK();
  681.       fprintf(trfp, "[Recv: subopt ");
  682.         if(opt <= NOPTIONS)
  683.             fprintf(trfp, "%s]\n",t_options[opt]);
  684.         else
  685.             fprintf(trfp, "%u]\n",opt);
  686.     }
  687.  
  688.     switch (SB_GET()) {
  689.     case TN_LFLOW:
  690.     if (tn->local[TN_LFLOW] == 0)
  691.         return;
  692.     if (SB_EOF())
  693.         return;
  694.     switch(SB_GET()) {
  695.     case 1:
  696.         tn->lflow = 1;
  697.         break;
  698.     case 0:
  699.         tn->lflow = 0;
  700.         break;
  701.     default:
  702.         return;
  703.     }
  704.     tel_setterm(tn);  /* get flow control right */
  705.     break;
  706.     case TN_TTYPE:
  707.     if (tn->local[TN_TTYPE] == 0)
  708.         return;
  709.     if (SB_EOF() || SB_GET() != 1) {
  710.         return;
  711.     } else {
  712.         char *name;
  713.         unsigned char temp[50];
  714.         int len;
  715.         struct mbuf *bp;
  716.  
  717.         name = getenv("TERM");
  718.         if(!name) name="tty";        /* dje hack 31-7-92 */
  719.         len = strlen(name) + 4 + 2;
  720.         if (len < sizeof(temp)) {
  721.         sprintf((char *)temp, "%c%c%c%c%s%c%c", IAC, SB, TN_TTYPE,
  722.                 0, name, IAC, SE);
  723.         bp = qdata((char *)temp,len);
  724.         send_tcp(tn->tcb,bp);
  725.         if (debug_options)
  726.           fprintf(trfp, "[Send: term %s]\n", name);
  727.         } else
  728.             return;
  729.     }
  730.     break;
  731.  
  732.     default:
  733.     break;
  734.     }
  735. }
  736.  
  737. static
  738. void
  739. answer(tn,r1,r2)
  740. struct telnet *tn;
  741. int r1,r2;
  742. {
  743.     struct mbuf *bp;
  744.     char s[3];
  745.  
  746.     if (debug_options) {
  747.       switch(r1){
  748.       case WILL:
  749.         fprintf(trfp, "[Sent: will ");
  750.         break;
  751.       case WONT:
  752.         fprintf(trfp, "[Sent: wont ");
  753.         break;
  754.       case DO:
  755.         fprintf(trfp, "[Sent: do ");
  756.         break;
  757.       case DONT:
  758.         fprintf(trfp, "[Sent: dont ");
  759.         break;
  760.       }
  761.       if(uchar(r2) <= NOPTIONS)
  762.         fprintf(trfp, "%s]\n",t_options[r2]);
  763.       else
  764.         fprintf(trfp, "%u]\n",r2);
  765.     }
  766.  
  767.     s[0] = IAC;
  768.     s[1] = r1;
  769.     s[2] = r2;
  770.     bp = qdata(s,(int16)3);
  771.     send_tcp(tn->tcb,bp);
  772. }
  773.  
  774. static struct svc
  775. {
  776. char *name;
  777. int service_code;
  778. } services[]={
  779.   "rje",5,
  780.   "echo",7,
  781.   "discard",9,
  782.   "users",11,
  783.   "daytime",13,
  784.   "netstat",15,
  785.   "quote",17,
  786.   "chargen",19,
  787.   "ftp-data",20,
  788.   "ftp",21,
  789.   "telnet",23,
  790.   "smtp",25,
  791.   "time",37,
  792.   "rlp",39,
  793.   "nameserver",42,
  794.   "nicname",43,
  795.   "domain",53,
  796.   "bootps",67,
  797.   "bootpc",58,
  798.   "tftp",69,
  799.   "finger",79,
  800.   "supdup",95,
  801.   "hostname",101,
  802.   "auth",113,
  803.   "uucp-path",117,
  804.   "nntp",119,
  805.   "ntp",123,
  806.   (char *)0,-1
  807.   };
  808.  
  809. int service_code(str)
  810. char *str;
  811. {
  812. char sp[20];
  813. char *cp, *ip ;
  814. int i;
  815. struct svc *svc = services;
  816. cp=sp; ip =str; 
  817.  
  818. if(!(i=strlen(str)) || i >19 )return(-1);
  819. /* if str is numeric, convert it to an integer */
  820. if( *str >='0' && *str <='9') return(atoi(str));  
  821. while(*ip != '\0'){ *cp++ = tolower(*ip); ip++; }
  822. *cp='\0';
  823. while( svc->name ){
  824.   if(!strcmp(svc->name,sp)) {
  825.     printf("%s service is code %d\n",str,svc->service_code);
  826.     return(svc->service_code);
  827.   }
  828.   svc++;
  829. }
  830. printf("Invalid service mnemonic %s\n",str);
  831.  
  832. return(-1);
  833. }
  834.